﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Principal;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace Nizm0.Chat.Messages
{
    public enum MessageType { client, server, system }

    public static class MessagesFromServer
    {
        public const string OK = "###__OK";
        public const string Cancel = "###__Cancel";
        public const string Disconnect = "###__Disconnect";
    }

    public static class MessagesFromKlient
    {
        public const string Require = "###__Require";
        public const string Disconnect = "###__Disconnect";
    }

    public interface IMessage
    {
        #region Properties

        User Sender
        {
            get;
        }
        //User Reciver
        //{
        //    get;
        //}
        DateTime SendDate
        {
            get;
        }
        DateTime ReciveDate
        {
            get;
            set;
        }
        bool IsPrivate
        {
            get;
        }
        #endregion

        IMessage Get();

    }

    [Serializable()]
    public abstract class Message : IMessage
    {
        private User _sender;
        //private User _receiver;
        private DateTime _sendDate;
        private DateTime _receiveDate;
        private bool _isPrivate = false;

        [NonSerialized]
        public System.Net.Sockets.Socket Socket;
        [NonSerialized]
        public List<byte> TransmissionBuffer = new List<byte>();
        [NonSerialized]
        public byte[] buffer = new byte[1024];


        public enum Type { Private, }

        public Message(User user)
        {
            _sender = user;
            _sendDate = DateTime.Now;
        }
        //public Message(User sender, User receiver)
        //{
        //    _sender = sender;
        //    _sendDate = DateTime.Now;
        //    _receiver = receiver;
        //}
        
        #region Properties

        public User Sender
        {
            get { return _sender; }
        }
        //public User Reciver
        //{
        //    get { return _receiver; }
        //}
        public DateTime SendDate
        {
            get { return _sendDate; }
        }
        public DateTime ReciveDate
        {
            get { return _receiveDate; }
            set { _receiveDate = value; }
        }
        public bool IsPrivate
        {
            get { return _isPrivate; }
        }
        #endregion

        #region Serialize
        public virtual byte[] Serialize(object o)
        {
            MemoryStream stream = new MemoryStream();

            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            formatter.Serialize(stream, o);
            //stream.Close();
            return stream.GetBuffer();
        }
        public virtual byte[] Serialize()
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            bin.Serialize(mem, this);
            return mem.GetBuffer();
        }
        public virtual Message DeSerialize(Stream stream)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            stream.Position = 0;
            Message o = (Message)formatter.Deserialize(stream);
            Console.WriteLine(o.GetType().ToString());
            //stream.Close();
            return o;
        }
        public virtual Message DeSerialize()
        {
            byte[] dataBuffer = TransmissionBuffer.ToArray();
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            mem.Write(dataBuffer, 0, dataBuffer.Length);
            mem.Seek(0, 0);
            return (Message)bin.Deserialize(mem);
        } 
        #endregion

        #region IMessage Members
        
        public virtual IMessage Get()
        {
            return this;
        }


        #endregion
    }

    [Serializable]
    public class TextMessage : Message
    {
        private User _receiver;
        private string _messageText;

        public User Reciver
        {
            get { return _receiver; }
        }
        public string MessageText
        {
            get { return _messageText; }
        }

        public TextMessage(User sender, User receiver, string str)
            : base(sender)
        {
            _receiver = receiver;
            _messageText = str;
        }
        public TextMessage(User user, string str)
            : base(user)
        {
            _messageText = str;
        }
        public TextMessage(User user)
            : base(user)
        {
            _messageText = "";
        }


        public override IMessage Get()
        {
            return this;
        }

        #region Serialize
        public override byte[] Serialize(object o)
        {
            MemoryStream stream = new MemoryStream();

            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            formatter.Serialize(stream, o);
            //stream.Close();
            return stream.GetBuffer();
        }
        public override byte[] Serialize()
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            bin.Serialize(mem, this);
            return mem.GetBuffer();
        }
        public TextMessage DeSerialize(Stream stream)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            stream.Position = 0;
            TextMessage o = (TextMessage)formatter.Deserialize(stream);
            Console.WriteLine(o.GetType().ToString());
            //stream.Close();
            return o;
        }
        public TextMessage DeSerialize()
        {
            byte[] dataBuffer = TransmissionBuffer.ToArray();
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            mem.Write(dataBuffer, 0, dataBuffer.Length);
            mem.Seek(0, 0);
            return (TextMessage)bin.Deserialize(mem);
        } 
        #endregion
    }

    [Serializable]
    public class LoginMessage : Message
    {
        //private User _messageUser;

        //public User MessageUser
        //{
        //    get { return _messageUser; }
        //}

        //public LoginMessage(User receiver, string str)
        //    : base(receiver)
        //{
        //    _messageUser = str;
        //}
        public LoginMessage(User user)
            : base(user)
        {
            //_messageUser = user;
        }
        //public LoginMessage()
        //    : base()
        //{
        //    _messageUser = "";
        //}


        public override IMessage Get()
        {
            return this;
        }

        #region Serialize
        public override byte[] Serialize(object o)
        {
            MemoryStream stream = new MemoryStream();

            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            formatter.Serialize(stream, o);
            //stream.Close();
            return stream.GetBuffer();
        }
        public override byte[] Serialize()
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            bin.Serialize(mem, this);
            return mem.GetBuffer();
        }
        public LoginMessage DeSerialize(Stream stream)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            stream.Position = 0;
            LoginMessage o = (LoginMessage)formatter.Deserialize(stream);
            Console.WriteLine(o.GetType().ToString());
            //stream.Close();
            return o;
        }
        public LoginMessage DeSerialize()
        {
            byte[] dataBuffer = TransmissionBuffer.ToArray();
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            mem.Write(dataBuffer, 0, dataBuffer.Length);
            mem.Seek(0, 0);
            return (LoginMessage)bin.Deserialize(mem);
        } 
        #endregion
    }

    [Serializable]
    public class StatusMessage : Message
    {
        public StatusMessage(User user) : base(user) { }
    }

    [Serializable]
    public class FileMessage : Message
    {
        String Name { get; set; }

        public FileMessage(User user) : base(user) { }
    }

    [Serializable]
    public class AskForMessage : Message
    {
        public AskForMessage(User user) : base(user) { }
    }

    [Serializable]
    public class ProcSendMessage : Message
    {
        public ProcSendMessage(User user) : base(user) { }
    }

    [Serializable]
    public class User
    {
        private string _name;
        [NonSerialized]
        private Socket _socked;
        private System.Net.IPEndPoint _ip;
        private Status _userStatus;

        public enum Status { Available, AFK, Busy, Hidden, Unavailable }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public Socket Socked
        {
            get { return _socked; }
            set { _socked = value; }
        }
        public System.Net.IPEndPoint Ip
        {
            get { return _ip; }
            set { _ip = value; }
        }
        public Status UserStatus
        {
            get { return _userStatus; }
            set { _userStatus = value; }
        }

        public User(string name, System.Net.IPEndPoint clientIP, Status status)
        {
            _name = name;
            _ip = clientIP;
            _userStatus = status;
        }
        public User(string name)
        {
            _name = name;
            _ip = new System.Net.IPEndPoint(System.Net.IPAddress.Any,8000);
            _userStatus = Messages.User.Status.Available;
        }

        public override string ToString()
        {
            return this._name;
        }
    }
}
